package jwlee.testnetwork;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;

import javax.swing.JOptionPane;

public class ChatClient {
	private static int clientid = 1;

	private static final int SERVER_PORT = 30000;

	private Socket socket;

	private PrintStream ps;

	private BufferedReader brServer;

	private BufferedReader keyIn;

	public void init() {
		try {
			// 初始化代表键盘的输入流
			keyIn = new BufferedReader(new InputStreamReader(System.in));

			// 连接到服务器
			socket = new Socket("127.0.0.1", SERVER_PORT);

			// 获取该Socket对应的输入流和输出流
			ps = new PrintStream(socket.getOutputStream());

			brServer = new BufferedReader(new InputStreamReader(socket
					.getInputStream()));

			String tip = "";

			// 采用循环不断地弹出对话框要求输入用户名
			while (true) {
				String userName = JOptionPane.showInputDialog(tip + "输入用户名");

				// 将用户输入的用户名的前后增加协议字符串后发送
				ps.println(ChatProtocol.USER_ROUND + userName
						+ ChatProtocol.USER_ROUND);

				// 读取服务器的响应
				String result = brServer.readLine();

				// 如果用户重复，开始下次循环
				if (result.equals(ChatProtocol.NAME_REP)) {
					tip = "用户名重复！请重新";
					continue;
				}

				// 如果服务器返回登录成功，结束循环
				if (result.equals(ChatProtocol.LOGIN_SUCCESS)) {
					break;
				}
			}
		} catch (IOException ex) {
			System.err.println("网络异常！请重新登录！" + ex.getMessage());
			closeRs();
			System.exit(1);
		}

		// 以该Socket对应的输入流启动ClientThread线程
		new Thread(new ClientThread(brServer)).start();
	}

	// 定义一个读取键盘输出，并向网络发送的方法
	private void readAndSend() {
		try {
			// 不断读取键盘输入
			String line = null;
			while ((line = keyIn.readLine()) != null) {
				// 如果发送的信息中有冒号，且以//开头，则认为想发送私聊信息
				if (line.indexOf(":") > 0 && line.startsWith("//")) {
					line = line.substring(2);
					ps.println(ChatProtocol.PRIVATE_ROUND + line.split(":")[0]
							+ ChatProtocol.SPLIT_SIGN + line.split(":")[1]
							+ ChatProtocol.PRIVATE_ROUND);
				} else {
					ps.println(ChatProtocol.MSG_ROUND + line
							+ ChatProtocol.MSG_ROUND);
				}
			}
		} catch (IOException ex) {
			System.err.println("网络通信异常！请重新登录！");
			closeRs();
			System.exit(1);
		}
	}

	// 关闭Socket、输入流、输出流的方法
	private void closeRs() {
		try {
			if (keyIn != null) {
				ps.close();
			}

			if (brServer != null) {
				ps.close();
			}

			if (ps != null) {
				ps.close();
			}

			if (socket != null) {
				keyIn.close();
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		}
	}

	public static void main(String[] args) {
		System.out.println("Client" + clientid++ + ":");
		ChatClient client = new ChatClient();
		client.init();
		client.readAndSend();
	}

	public class ClientThread extends Thread {
		// 该客户端线程负责处理的输入流
		BufferedReader br = null;

		// 使用一个网络输入流来创建客户端线程
		public ClientThread(BufferedReader br) {
			this.br = br;
		}

		public void run() {
			try {
				String line = null;
				// 不断从输入流中读取数据，并将这些数据打印输出
				while ((line = br.readLine()) != null) {
					System.out.println(line);
					/*
					 * 
					 * 本例仅打印了从服务器端读到的内容。实际上，此处的情况可以更复杂：
					 * 
					 * 如果我们希望客户端能看到聊天室的用户列表，则可以让服务器在
					 * 
					 * 每次有用户登录、用户退出时，将所有用户列表信息都向客户端发送一遍。
					 * 
					 * 为了区分服务器发送的是聊天信息，还是用户列表，服务器也应该
					 * 
					 * 在要发送的信息前、后都添加一定的协议字符串，客户端此处则根据协议
					 * 
					 * 字符串的不同而进行不同的处理！
					 * 
					 * 更复杂的情况：
					 * 
					 * 如果两端进行游戏，则还有可能发送游戏信息，例如两端进行五子棋游戏，
					 * 
					 * 则还需要发送下棋坐标信息等，服务器同样在这些下棋坐标信息前、后
					 * 
					 * 添加协议字符串后再发送，客户端就可以根据该信息知道对手的下棋坐标。
					 */

				}
			} catch (IOException ex) {
				ex.printStackTrace();
			} finally {
				try {
					if (br != null) {
						br.close();
					}
				} catch (IOException ex) {
					ex.printStackTrace();
				}
			}
		}
	}
}
